﻿using FySystem.AssistantServices;
using FySystem.Converter;
using FySystem.Extension;
using FySystem.IO;
using FySystem.Net.SimSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FySystem.Net.LSTP
{
    /// <summary>
    /// LSTP监听程序
    /// </summary>
    public class LSTPListener:LSTPBase
    {
        private List<LSTPConnection> _connections = new List<LSTPConnection>();

        /// <summary>
        /// 收到客户端连接回调
        /// </summary>
        public Action<LSTPConnection> OnAcceptCallback { get; set; }

        /// <summary>
        /// 断开连接
        /// </summary>
        public Action<LSTPConnection> OnDisconnect { get; set; }

        /// <summary>
        /// 创建LSTP监听程序
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        public LSTPListener(IPAddress ipAddress, int port)
        {
            IP = ipAddress;
            Port = port;
        }

        /// <summary>
        /// 开始监听（异步）
        /// </summary>
        public void Listen(Action<LSTPConnection> onAccept, Action<LSTPRequest, LSTPWebResponse> onRequest)
        {
            try
            {
                OnAcceptCallback = onAccept;
                OnRequestCallback = onRequest;

                IAssistantServiceContext assistantServiceContext = AssistantServiceContext.CreateService(30, false);

                //初始化网络服务
                assistantServiceContext.AddService<SimServer>("sev").Configure(service =>
                {
                    SimServer server = (SimServer)service;
                    server.IpAddress = IP;
                    server.Port = Port;
                    server.OnAccept = OnAccept;
                    server.OnException = OnException;
                    server.OnReceive = OnReceive;
                    server.OnConnectionGC = OnGC;
                });

                assistantServiceContext.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        /// <summary>
        /// 根据名称查找连接
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public LSTPConnection FindConnection(string name)
        {
            LSTPConnection res = null;
            try
            {
                if (string.IsNullOrWhiteSpace(name))
                    throw new Exception("传入name为空~");

                lock (_connections)
                {
                    foreach(var item in _connections)
                    {
                        if (item.Name == name)
                        {
                            res = item;
                            break;
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 客户端连入
        /// </summary>
        /// <param name="client"></param>
        private void OnAccept(SimClient client)
        {
            try
            {
                LSTPConnection connection = new LSTPConnection(client);
                _connections.Add(connection);
                client.Tag = connection;

                OnAcceptCallback?.Invoke(connection);
            }
            catch (Exception ex)
            {
                FyLogContext.Write(ex.Message);
            }
        }

        /// <summary>
        /// 收到数据
        /// </summary>
        /// <param name="client"></param>
        /// <param name="frame"></param>
        protected void OnReceive(SimClient client, FrameInfo frame)
        {
            try
            {
                int position = 0;
                CSon cSon = CSon.Parse(frame.Frame.AsSpan(), ref position, frame.Frame.Length);

                if (IsRequest(cSon))
                {
                    //如果收到的是request
                    LSTPRequest request = new LSTPRequest();
                    request.Connection = (LSTPConnection)client.Tag;

                    //将收到的请求转换为request
                    DecodeRequest(request, cSon);

                    //创建response并进行response回调
                    List<byte> bytes = null;
                    CreateResponseAndCallback(request, ref bytes);

                    //将response数据返回给远端
                    request.Connection.SimClient.Send(bytes);
                }
                else
                {
                    //如果收到的是response
                    LSTPResponse response = new LSTPResponse();
                    response.RequestId = cSon["requestId"].BytesValue;
                    response.Status = cSon["status"].IntValue;
                    response.Error = cSon["error"].StringValue;
                    response.Body = cSon["body"];

                    var connection = (LSTPConnection)client.Tag;

                    string strRequestId = NumberConversion.BytesToHexString(response.RequestId, 0, 16, false);
                    connection.DistributorRequest(strRequestId, response);
                }
            }
            catch (Exception ex)
            {
                FyLogContext.Write(ex.Message);
            }
        }

        private void OnException(Exception arg1, SimClient arg2)
        {
            //FyLogContext.Write(arg1.Message);
        }

        /// <summary>
        /// 删除失效连接
        /// </summary>
        /// <param name="simClient"></param>
        private void OnGC(SimClient simClient)
        {
            try
            {
                LSTPConnection conn = null;
                lock (_connections)
                {
                    foreach (var item in _connections)
                    {
                        if (item.SimClient.SimStateObject.ID == simClient.SimStateObject.ID)
                        {
                            conn = item;
                            break;
                        }
                    }

                    if (conn != null)
                        _connections.Remove(conn);
                }

                if (conn != null && OnDisconnect != null)
                    OnDisconnect.Invoke(conn);
            }
            catch (Exception ex)
            {
                FyLogContext.Write(ex.Message);
            }
        }
    }
}
